package cn.edu.hebtu.www.clubassembly;

import org.apache.commons.httpclient.ConnectTimeoutException;
import org.apache.commons.httpclient.NoHttpResponseException;
import org.apache.http.HttpEntityEnclosingRequest;
import org.apache.http.HttpRequest;
import org.apache.http.client.HttpRequestRetryHandler;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.protocol.HttpClientContext;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.protocol.HttpContext;

import javax.net.ssl.SSLException;
import java.io.IOException;
import java.io.InterruptedIOException;
import java.net.UnknownHostException;
import java.util.logging.Logger;

/**
 * Created by root on 16-3-12.
 */
public class HttpClientFactory {
    private static final Logger logger = Logger.getLogger(HttpClientFactory.class.getName());
    private static final Integer DEFAULT_MAX_RETRY_COUNT = Integer.valueOf(3);
    private static final Integer DEFAULT_HTTP_TIMEOUT_SECONDS = Integer.valueOf(50);

    public HttpClientFactory() {
    }

    public static CloseableHttpClient getHttpClientWithRetry() {
        return getHttpClientWithRetry(DEFAULT_MAX_RETRY_COUNT);
    }

    public static CloseableHttpClient getHttpClientWithRetry(Integer maxRetryCount) {
        return HttpClients.custom().setDefaultRequestConfig(getRequestConfig(DEFAULT_HTTP_TIMEOUT_SECONDS)).setRetryHandler(getHttpRequestRetryHandler(maxRetryCount)).build();
    }

    private static HttpRequestRetryHandler getHttpRequestRetryHandler(final Integer maxRetryCount) {
        HttpRequestRetryHandler myRetryHandler = new HttpRequestRetryHandler() {
            public boolean retryRequest(IOException exception, int executionCount, HttpContext context) {
                if(executionCount > maxRetryCount.intValue()) {
                    HttpClientFactory.logger.info("Over the max retry count. Skip retrying.");
                    return false;
                } else if(exception instanceof InterruptedIOException) {
                    HttpClientFactory.logger.info("No retry." + exception.getMessage());
                    return false;
                } else if(exception instanceof UnknownHostException) {
                    HttpClientFactory.logger.info("No retry." + exception.getMessage());
                    return false;
                } else if(exception instanceof ConnectTimeoutException) {
                    HttpClientFactory.logger.info("Need retry." + exception.getMessage());
                    return true;
                } else if(exception instanceof SSLException) {
                    HttpClientFactory.logger.info("No retry." + exception.getMessage());
                    return false;
                } else if(exception instanceof NoHttpResponseException) {
                    HttpClientFactory.logger.info("Need retry." + exception.getMessage());
                    return true;
                } else {
                    HttpClientContext clientContext = HttpClientContext.adapt(context);
                    HttpRequest request = clientContext.getRequest();
                    boolean idempotent = !(request instanceof HttpEntityEnclosingRequest);
                    return idempotent;
                }
            }
        };
        return myRetryHandler;
    }

    private static RequestConfig getRequestConfig(Integer timeout) {
        return RequestConfig.custom().setSocketTimeout(timeout.intValue() * 1000).setConnectTimeout(timeout.intValue() * 1000).build();
    }
}
